using System;
using System.Collections.Generic;
using NFreeMarker.Template;
using NFreeMarker.Template.Utility;

namespace NFreeMarker.Ext.Beans
{
    /**
     * Base class for hash models keyed by Java class names. 
     * @author Attila Szegedi
     * @version $Id: ClassBasedModelFactory.java,v 1.1.2.2 2006/11/12 10:23:02 szegedia Exp $
     */
    abstract class ClassBasedModelFactory : ITemplateHashModel
    {
        private readonly BeansWrapper _wrapper;
        private readonly Dictionary<string, ITemplateModel> _cache = new Dictionary<string, ITemplateModel>();
        
        protected ClassBasedModelFactory(BeansWrapper wrapper)
        {
            _wrapper = wrapper;
        }

        public ITemplateModel Get(string key)
        {
            lock (_cache)
            {
                ITemplateModel model = _cache.GetValueOrDefault(key);
                if (model == null)
                {
                    try
                    {
                        Type type = ClassUtil.ForName(key);
                        model = CreateModel(type);
                        // This is called so that we trigger the
                        // class-reloading detector. If there was a class reload,
                        // the wrapper will in turn call our clearCache method.
                        _wrapper.IntrospectClass(type);
                    }
                    catch(Exception e)
                    {
                        throw new TemplateModelException(e);
                    }
                    _cache.Add(key, model);
                }
                return model;
            }
        }
        
        internal void ClearCache()
        {
            lock (_cache)
            {
                _cache.Clear();
            }
        }
        
        internal void RemoveIntrospectionInfo(Type type)
        {
            lock (_cache)
            {
                _cache.Remove(type.FullName);
            }
        }

        public bool IsEmpty()
        {
            return false;
        }
        
        protected abstract ITemplateModel CreateModel(Type type);
        
        protected BeansWrapper GetWrapper()
        {
            return _wrapper;
        }
    }
}